// 实用工具模块
/*
    获取当前时间
    判断文件是否存在
    获取文件路径(目录)
    创建目录
*/
#pragma once

#include "except.hpp"
#include <iostream>
#include <unordered_map>
#include <exception>
#include <string>
#include <ctime>
#include <sys/types.h>
#include <sys/stat.h>

//区分Windows和Linux
#ifdef _WIN32
#include <direct.h>
#include <windows.h>
#elif __linux__
#include <unistd.h>
#endif

namespace easylog
{
    namespace util
    {
        //日志信息中的行，函数，文件信息
        class source_loc
        {   
        public:
            source_loc(const char* file = __builtin_FILE(),
                       const char* function = __builtin_FUNCTION(),
                       const int line = __builtin_LINE())
                       :_file(file), _function(function), _line(line)
            {}

            const char* _file;
            const char* _function;
            int _line;
        };
        //时间类
        class Date
        {
        public:
            // 获取当前时间
            static size_t getTime()
            {
                return (size_t)time(nullptr);
            }
        };
        //文件类
        class File
        {
        public:
            // 判断文件是否存在
            static bool isFileExist(const std::string &pathname)
            {
                struct stat st;
                // 获取文件信息，如果获取得到，说明文件存在
                if (stat(pathname.c_str(), &st) == 0)
                    return true;
                return false;
            }

            // 获取文件路径
            static std::string getPath(const std::string &pathname)
            {
                int pos = pathname.find_last_of("/\\");
                if (pos == std::string::npos)
                    return ".";
                // ./abc/a.txt  最后一个/下标为5，pos + 1将最后'/'也截取
                return pathname.substr(0, pos + 1);
            }

            // 创建目录
            static void createPath(const std::string &pathname)
            {
                int pos = 0, start = 0;
                while (pos < pathname.size())
                {
                    pos = pathname.find('/', start);
                    // 没有路径了
                    if (pos == std::string::npos)
                    {
                        mkdir(pathname.c_str(), 0777);
                        break;
                    }
                    std::string tmp = pathname.substr(0, pos + 1);
                    if (!isFileExist(tmp))
                        mkdir(tmp.c_str(), 0777);
                    start = pos + 1;
                }
            }
        };
        //颜色类
        class color
        {
        public:
            // 颜色集合体
            enum color_enum
            {
                none = 0,
                black,
                light_black,
                red,
                light_red,
                green,
                light_green,
                yellow,
                light_yellow,
                blue,
                light_blue,
                purple,
                light_purple,
                cyan,
                light_cyan,
                white,
                light_white,
            };
            //返回相应颜色的转义符
            static const char* onclr(color_enum cl)
            {
                if(_cols.find(cl) == _cols.end())
                    throw except("util::color: unknow color");
                return _cols[cl];
            }
            //取消颜色
            static const char* offclr()
            {
                return "\033[0m";
            }
            //保存颜色和转义符映射关系的哈希表
            static std::unordered_map<int, const char *> _cols; 
        };
        //成员变量，记录颜色枚举类和对应转义字符的哈希表
        std::unordered_map<int, const char*> color::_cols = {
                    {         color_enum::none, "\033[0m"    }, //none
                    {        color_enum::black, "\033[0;30m" }, //black
                    {  color_enum::light_black, "\033[1;30m" }, //light_black
                    {          color_enum::red, "\033[0;31m" }, //red
                    {    color_enum::light_red, "\033[1;31m" }, //light_red
                    {        color_enum::green, "\033[0;32m" }, // green
                    {  color_enum::light_green, "\033[1;32m" }, // light_green
                    {       color_enum::yellow, "\033[0;33m" }, // brown
                    { color_enum::light_yellow, "\033[1;33m" }, // yellow
                    {         color_enum::blue, "\033[0;34m" }, // blue
                    {   color_enum::light_blue, "\033[1;34m" }, // light_blue
                    {       color_enum::purple, "\033[0;35m" }, // purple
                    { color_enum::light_purple, "\033[1;35m" }, // light_purple
                    {         color_enum::cyan, "\033[0;36m" }, // cyan
                    {   color_enum::light_cyan, "\033[1;36m" }, // light_cyan
                    {        color_enum::white, "\033[0;37m" }, // light_gray
                    {  color_enum::light_white, "\033[1;37m" }, // white
                };
    }
}
